package com.haiyang.gateway.config;

import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * @BelongsProject: ms
 * @BelongsPackage: com.haiyang.gateway.config
 * @Author: BHY
 * @CreateTime: 2023-11-01  20:37
 * @Description: 动态鉴权
 * @Version: 1.0
 */
@Component
public class GatewayReactiveAuthorizationManager implements ReactiveAuthorizationManager<AuthorizationContext>{
    private AuthenticationTrustResolver authTrustResolver = new AuthenticationTrustResolverImpl();

    // 验证通过则返回：AuthorizationDecision(true)
    // 验证失败则返回：AuthorizationDecision(false)
    @Override
    public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, AuthorizationContext context) {
        return authentication
                .filter(authentication_filter -> select_context(authentication_filter, context))
                .map(authentication_map -> authenticate(authentication_map, context))
                .defaultIfEmpty(new AuthorizationDecision(false));
    }
    private boolean select_context(Authentication authentication, AuthorizationContext context) {
        // String req_path = context.getExchange().getRequest().getURI().getPath();
        // log.info("check filter path: {}", req_path);
        return !this.authTrustResolver.isAnonymous(authentication);
    }
    private AuthorizationDecision authenticate(Authentication authentication, AuthorizationContext context) {
        if (authentication.isAuthenticated()) {
            // 判断context.getExchange().getRequest().getPath()是否在authentication_notanonymous.getAuthorities()集合中
            String req_path = context.getExchange().getRequest().getURI().getPath();
            OidcUser principal = (OidcUser)authentication.getPrincipal();
            OidcIdToken idToken = principal.getIdToken();
            List<String> authorities = (List)idToken.getClaims().get("authorities");
            //if (authorities.contains(new GatewayUserGrantedAuthority(req_path)) == false) {
            //    return new AuthorizationDecision(true);
            //}
            AntPathMatcher antPathMatcher = new AntPathMatcher();
            for(String auth : authorities){
                if(antPathMatcher.match(auth,req_path)){
                    return new AuthorizationDecision(true);
                }
            }
            return new AuthorizationDecision(false);
        }
        return new AuthorizationDecision(authentication.isAuthenticated());
    }
}
